package com.dap.batch.controller;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.dap.batch.constant.BatchConstant;
import com.dap.batch.dao.IDaoService;
import com.dap.batch.entity.Result;
import com.dap.batch.enums.ResultEnum;
import com.dap.batch.exception.BatchCustomException;
import com.dap.batch.po.BatchSchedulePo;
import com.dap.batch.service.IBatchSchedulerBroker;
import com.dap.batch.utils.ResultUtils;
import com.dap.dao.model.QueryResult;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;


/**
 * @description: 类描述
 * @author: Fesine
 * @createTime:2017/9/28 15:59
 * @update:修改内容
 * @author: Fesine
 * @updateTime:2017/9/28 15:59
 */
@RestController
@RequestMapping("/v1")
public class BatchScheduleController {

    private final static Logger logger = LoggerFactory.getLogger(BatchScheduleController.class);



    private IDaoService daoService;
    private IBatchSchedulerBroker broker;

    @Autowired
    public BatchScheduleController(IDaoService daoService, IBatchSchedulerBroker broker) {
        this.daoService = daoService;
        this.broker = broker;
    }

    /**
     * 查询所有定时配置数据
     *
     * @param groupId
     * @param status
     * @param page
     * @param limit
     * @return
     */
    @ApiOperation(value = "分页获取定时配置信息", httpMethod = "GET")
    @GetMapping("/schedules")
    public Result list(@RequestParam(required = false) String groupId
            , @RequestParam(required = false) Short status
            , @RequestParam(defaultValue = "1") Integer page
            , @RequestParam(defaultValue = "10") Integer limit) {
        BatchSchedulePo po = new BatchSchedulePo();
        if (!StringUtils.isEmpty(status)) {
            po.setStatus(status);
        }
        if (!StringUtils.isEmpty(groupId)) {
            StringBuffer sb = new StringBuffer("%");
            sb.append(groupId).append("%");
            po.setGroupId(sb.toString());
        }
        String mapper = BatchSchedulePo.class.getName() + BatchConstant.SELECT_LIKE;
        QueryResult<BatchSchedulePo> result = daoService.selectQueryResult(mapper, po,
                page, limit);
        if (result.getTotalrecord() == 0) {
            throw new BatchCustomException(ResultEnum.NOT_FOUND);
        }
        return ResultUtils.success(result);
    }

    /**
     * 添加定时任务
     * @param po
     * @return
     */
    @ApiOperation(value = "添加定时任务", httpMethod = "POST")
    @PostMapping("/schedule")
    public Result add(BatchSchedulePo po) {
        try {
            po.setId(po.getGroupId());
            daoService.insert(po);
            //如果添加时状态为1，则需要注册服务
            if (po.getStatus() == 1) {
                this.scheduleGroup(po.getId(), BatchConstant.METHOD_ADD);
            }
        } catch (Exception e) {
            logger.error("添加失败", e);
            throw new BatchCustomException(ResultEnum.INTERNAL_SERVER_ERROR);
        }
        return ResultUtils.success(ResultEnum.CREATED);
    }

    /**
     * 更新操作时id、status必须传
     * 其他字段需要更新时传入
     *
     * @param schedulePo
     * @return
     */
    @ApiOperation(value = "修改定时任务", httpMethod = "PUT")
    @PutMapping("/schedule")
    public Result update(BatchSchedulePo schedulePo) {
        try {
            //先根据id更新数据库
            daoService.update(schedulePo);
            //再根据状态判断是注册定时器还是注销定时器
            if (schedulePo.getStatus() == 1) {
                this.scheduleGroup(schedulePo.getId(), BatchConstant.METHOD_ADD);
            } else {
                this.scheduleGroup(schedulePo.getId(), BatchConstant.METHOD_DELETE);
            }
            return ResultUtils.success(ResultEnum.CREATED);
        } catch (Exception e) {
            logger.error("操作失败", e);
            throw new BatchCustomException(ResultEnum.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 删除定时任务
     *
     * @param id
     * @return
     */
    @ApiOperation(value = "根据ID删除定时任务", httpMethod = "DELETE")
    @DeleteMapping("/schedule/{id}")
    public Result delete(@PathVariable String id) {
        try {
            BatchSchedulePo schedulePo = new BatchSchedulePo();
            schedulePo.setId(id);
            schedulePo = daoService.selectOne(schedulePo);
            if (schedulePo.getStatus() == 1) {
                //注销定时器
                this.scheduleGroup(id, BatchConstant.METHOD_DELETE);
            }
            //删除记录，注销时会将状态改为0，因此需要重新根据id删除配置
            schedulePo = new BatchSchedulePo();
            schedulePo.setId(id);
            daoService.delete(schedulePo);
            return ResultUtils.success(ResultEnum.DELETED);
        } catch (Exception e) {
            logger.error("操作失败", e);
            throw new BatchCustomException(ResultEnum.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 定时任务操作
     * @param method
     * @return
     */
    @ApiOperation(value = "定时器操作：停止、启动、重启", httpMethod = "POST")
    @PostMapping("/schedule/{method}")
    public Result execute(@PathVariable String method) {
        try {
            if (method.equals(BatchConstant.METHOD_START)) {
                broker.startScheduler();
            } else if (method.equals(BatchConstant.METHOD_STOP)) {
                broker.stopScheduler();
            } else if (method.equals(BatchConstant.METHOD_INIT)) {
                broker.stopScheduler();
                //将所有已经启动的定时任务进行重置
                BatchSchedulePo bsp = new BatchSchedulePo();
                bsp.setStatus(Short.valueOf("1"));
                List<BatchSchedulePo> list = daoService.selectList(bsp);
                if (CollectionUtils.isNotEmpty(list)) {
                    for (BatchSchedulePo bs : list) {
                        //重新注册定时任务
                        broker.schedule(bs.getGroupId(), 0);
                    }
                }
                //启动定时器
                broker.startScheduler();
            }
            return ResultUtils.success(ResultEnum.CREATED);
        } catch (Exception e) {
            logger.error("操作失败", e);
            throw new BatchCustomException(ResultEnum.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 查询当前定时器状态
     * @return
     */
    @ApiOperation(value = "获取定时器状态", httpMethod = "GET")
    @GetMapping("/schedule/mode")
    public Result isStandByMode() {
        boolean isStandByMode = broker.isStandByMode();
        return ResultUtils.success(isStandByMode);
    }

    /**
     * 获取定时计划
     * @return
     */
    @ApiOperation(value = "获取所有定时计划", httpMethod = "GET")
    @GetMapping("/schedule/plans")
    public Result plan() {
        try {
            return ResultUtils.success(broker.listScheduledGroups());
        } catch (Exception e) {
            logger.error("查询失败", e);
            throw new BatchCustomException(ResultEnum.NOT_FOUND);
        }
    }

    /**
     * 因为id==groupId
     * 1、判断是新增还是删除
     * 2、新增，注册定时器
     * 3、删除，注销定时器
     *
     * @param id
     * @param method
     */
    private Result scheduleGroup(String id, String method) {
        try {
            if (method.equals(BatchConstant.METHOD_ADD)) {
                broker.schedule(id, 0);
            } else if (method.equals(BatchConstant.METHOD_DELETE)) {
                broker.unschedule(id);
            }
            return ResultUtils.success(ResultEnum.CREATED);
        } catch (Exception e) {
            logger.error("操作失败", e);
            throw new BatchCustomException(ResultEnum.INTERNAL_SERVER_ERROR);
        }
    }

}
